﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Excel;
using Redmine.Laptop.Common.Core.Enums;

namespace Redmine.Laptop.Common.Core
{
    public class ExcelDocument : IDisposable
    {
        private Application _application;
        private Workbook _workBook;
        private Worksheet _workSheet;

        public ExcelDocument()
        {
            _application = new Application { Visible = false };
            _workBook = _application.Workbooks.Add();
            _workSheet = _workBook.ActiveSheet;
        }
        
        /// <summary>
        /// Set background color
        /// </summary>
        /// <param name="color">Color</param>
        /// <param name="range1"></param>
        /// <param name="range2"></param>
        [Obsolete]
        public void SetBackground(Color color, string range1, string range2)
        {
            var range = _workSheet.Range[range1, range2];
            range.Interior.Color = ColorTranslator.ToOle(color);
        }

        /// <summary>
        /// Set background color
        /// </summary>
        /// <param name="color">Color</param>
        /// <param name="row1"></param>
        /// <param name="column1"></param>
        /// <param name="row2"></param>
        /// <param name="column2"></param>
        public void SetBackground(Color color, uint row1, uint column1, uint row2, uint column2)
        {
            var range1 = this[row1, column1];
            var range2 = this[row2, column2];
            _workSheet.Range[range1, range2].Interior.Color = ColorTranslator.ToOle(color);
        }
        
        public void SetFontSize(uint fontSize, uint row1, uint column1, uint row2, uint column2)
        {
            var range1 = this[row1, column1];
            var range2 = this[row2, column2];
            _workSheet.Range[range1, range2].Font.Size = fontSize;
        }

        public void SetFontColor(Color color, uint row1, uint column1, uint row2, uint column2)
        {
            var range1 = this[row1, column1];
            var range2 = this[row2, column2];
            _workSheet.Range[range1, range2].Font.Color = color;
        }

        public void SetFontColor(Color color, uint row1, uint column1, uint row2, uint column2, uint startCharacter, uint lengthCharacter)
        {
            var range1 = this[row1, column1];
            var range2 = this[row2, column2];
            _workSheet.Range[range1, range2].Characters[startCharacter, lengthCharacter].Font.Color = color;
        }

        public void SetTextAlignment(CellAlignment alignment, uint rowIndex, uint columnIndex)
        {
            _workSheet.Cells[rowIndex, columnIndex].HorizontalAlignment = alignment;
        }

        public void SetBoldFont(uint row1, uint column1, uint row2, uint column2)
        {
            var range1 = this[row1, column1];
            var range2 = this[row2, column2];
            _workSheet.Range[range1, range2].Font.Bold = true;
        }
        
        public void SetBorder(uint row1, uint column1, uint row2, uint column2, Color color, BorderWeight weight = BorderWeight.Medium, LineStyle lineStyle = LineStyle.Solid, bool isDrawAllBorders = true, bool isDrawLeftEdge = false, bool isDrawTopEdge = false, bool isDrawRightEdge = false, bool isDrawBottomEdge = false)
        {
            var range1 = this[row1, column1];
            var range2 = this[row2, column2];

            var edges = new List<XlBordersIndex>(4);

            if (isDrawLeftEdge)
                edges.Add(XlBordersIndex.xlEdgeLeft);
            if (isDrawTopEdge)
                edges.Add(XlBordersIndex.xlEdgeTop);
            if (isDrawRightEdge)
                edges.Add(XlBordersIndex.xlEdgeRight);
            if (isDrawBottomEdge)
                edges.Add(XlBordersIndex.xlEdgeBottom);

            var range = _workSheet.Range[range1, range2];

            if (isDrawAllBorders)
            {
                range.Borders.LineStyle = lineStyle;
                range.Borders.Color = ColorTranslator.ToOle(color);
                range.Borders.Weight = weight;
            }
            else
                foreach (var edgeIndex in edges)
                {
                    range.Borders[edgeIndex].Color = ColorTranslator.ToOle(color);
                    range.Borders[edgeIndex].Weight = weight;
                    range.Borders[edgeIndex].LineStyle = lineStyle; 
                }

            edges.Clear();
        }

        public object this[uint rowIndex, uint columnIndex]
        {
            get { return _workSheet.Cells[rowIndex, columnIndex]; }
            set { _workSheet.Cells[rowIndex, columnIndex] = value; }
        } 
        
        /// <summary>
        /// Save document to disk
        /// </summary>
        /// <param name="path">Saving path</param>
        /// <returns></returns>
        public FileStorage Save(string path)
        {
            _workSheet.Columns.AutoFit();
            _workBook.SaveAs(path, AccessMode: XlSaveAsAccessMode.xlShared);
            _workBook.Close();
            _application.Quit();

            return new FileStorage(path);
        }

        /// <summary>
        /// Dispose object
        /// </summary>
        public void Dispose()
        {
            Marshal.ReleaseComObject(_application);
            Marshal.ReleaseComObject(_workBook);
            Marshal.ReleaseComObject(_workSheet);

            _application = null;
            _workBook = null;
            _workSheet = null;
        }
    }
}
